#include <stdio.h>
#include <stdlib.h>

#include "platforms/gpio.h"
#include "platforms/spi.h"

#include "drivers/lcd/st7789.h"

int colorbar_generate(uint8_t* buf, int width, int height)
{
	int row = 0; // 行
	int col = 0; // 列
	int num = 0; // 彩条序号
	int w = 0;   // 单行彩条的宽度

	/**
	 * colorbar 彩条一共8种颜色，由红绿蓝3色排列组合而来
	 * 颜色格式为 RGB565
	 */
	uint16_t color[8] = {
		0x0000, // 黑 0000 0000 0000 0000
		0x001F, // 蓝 0000 0000 0001 1111
		0x07E0, // 绿 0000 0111 1110 0000
		0x07FF, // 青 0000 0111 1111 1111
		0xF800, // 红 1111 1000 0000 0000
		0xF81F, // 紫 1111 1000 0001 1111
		0xFFE0, // 黄 1111 1111 1110 0000
		0xFFFF, // 白 1111 1111 1111 1111
	};

	if (NULL == buf) {
		return -1;
	}

	w = width / 8;

	for (row = 0; row < height; row++) {
		for (num = 0; num < 8; num++) {
			for (col = w * num; col < w * (num + 1); col++) {
				/* 高字节在前, 低字节在后 */
				*(buf + (width * row + col) * 2) = color[num] >> 8;
				*(buf + (width * row + col) * 2 + 1) = color[num] & 0xff;
			}
		}
	}

	return 0;
}

#define ST7789_CS_PIN  121 // PD25
#define ST7789_RST_PIN 119 // PD23
#define ST7789_DC_PIN  120 // PD24
#define ST7789_BL_PIN  118 // PD22

static spi_t spi;

void esp32c3_spi_write(uint8_t* bytes, uint32_t len)
{
	/* 单次最多传输 4096 个字节 */
	uint32_t section = 4096;

	if (!len) {
		return;
	}

	while (len > section) {
		spi_write(spi, bytes, section);
		bytes += section;
		len -= section;
	}

	spi_write(spi, bytes, len);
}

static void esp32c3_rst_pin(int val)
{
	gpio_set(ST7789_RST_PIN, val);
}

static void esp32c3_dc_pin(int val)
{
	gpio_set(ST7789_DC_PIN, val);
}

static void esp32c3_bl_pin(int val)
{
	gpio_set(ST7789_BL_PIN, val);
}

static void esp32c3_msleep(int ms)
{
	usleep(1000 * ms);
}

static void board_init()
{
	spi_conf_t conf;

	/* gpio */
	gpio_dir(ST7789_RST_PIN, GPIO_E_OUTPUT);
	gpio_dir(ST7789_DC_PIN, GPIO_E_OUTPUT);
	gpio_dir(ST7789_BL_PIN, GPIO_E_OUTPUT);

	/* spi */
	conf.mode = SPI_E_MODE_0;
	conf.speed = 20000000;
	spi = spi_init(conf);
	if (spi == NULL) {
		printf("err: spi init\n");
	}
}

int main()
{
	struct st7789 lcd;
	uint8_t* buf_h = NULL;
	uint8_t* buf_v = NULL;

	/* board init */
	board_init();

	/* set lcd param */
	lcd.cfg.fix.width = 240;
	lcd.cfg.fix.height = 280;
	lcd.cfg.fix.xshift = 0;
	lcd.cfg.fix.yshift = 20;
	lcd.cfg.fix.bits = 8;
	lcd.cfg.var.orien = ROTATE_0;

	/* register the operation */
	lcd.ops.reset = esp32c3_rst_pin;
	lcd.ops.datacmd = esp32c3_dc_pin;
	lcd.ops.backlight = esp32c3_bl_pin;
	lcd.ops.msleep = esp32c3_msleep;
	lcd.ops.write = esp32c3_spi_write;
	st7789_init(&lcd);

	/* malloc buf */
	buf_h = malloc(lcd.cfg.fix.width * lcd.cfg.fix.height * 2);
	colorbar_generate(buf_h, lcd.cfg.fix.height, lcd.cfg.fix.width);

	buf_v = malloc(lcd.cfg.fix.width * lcd.cfg.fix.height * 2);
	colorbar_generate(buf_v, lcd.cfg.fix.width, lcd.cfg.fix.height);

	while (1) {
		st7789_rotate_set(&lcd, ROTATE_0);
		st7789_rect_fill(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, (uint16_t*)buf_v);
		sleep(1);

		st7789_rotate_set(&lcd, ROTATE_90);
		st7789_rect_fill(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, (uint16_t*)buf_h);
		sleep(1);

		st7789_rotate_set(&lcd, ROTATE_180);
		st7789_rect_fill(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, (uint16_t*)buf_v);
		sleep(1);

		st7789_rotate_set(&lcd, ROTATE_270);
		st7789_rect_fill(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, (uint16_t*)buf_h);
		sleep(1);
	}

	free(buf_h);
	free(buf_v);

	return 0;
}
